const int PIN_ONOFF = 22;

void onOff()
{
  digitalWrite(PIN_ONOFF, HIGH);
  delay(1200);
  digitalWrite(PIN_ONOFF, LOW);
}

/*int esperaInSerial3(unsigned long milisEspera)
{
  if (Serial3.available())
    return true; 
  unsigned long start = millis();
  for (;;) {
    if ((millis() - start) > milisEspera)
      return false;
    if (Serial3.available())
      return true;
  }
}*/

int esperaInSerial3(unsigned long milisEspera, char c)
{
  unsigned long start = millis();
  for (;;) {
    if ((millis() - start) > milisEspera)
      return 0;
    if (Serial3.available())
    {
      int leido = Serial3.read();
      
      if (leido == c)
      {
         Serial.print((char) leido);
         return 1;
      }
      else
      {
         Serial.print((char) leido);
         return 0;
      }
    }
  }
}

void limpiarSerial3()
{
  while(Serial3.available())
    Serial3.read();
}

int esperaRespuesta (String respuesta, unsigned long esperaInicial, unsigned long esperaEntreChar)
{
  for (int i=0; i < respuesta.length(); i++) {
    if (i == 0) {
      if (! esperaInSerial3(esperaInicial, respuesta[i]))
        return 0;
    } else {
      if (! esperaInSerial3(esperaEntreChar, respuesta[i]))
        return 0;
    }
  }
      
  return 1;
}

int adjuntoALaRed ()
{
  Serial3.write("AT+CGATT?\r\n");
  return esperaRespuesta (
    "AT+CGATT?\r\n\r\n+CGATT: 1\r\n\r\nOK\r\n", 
    500, 100
  );
}

int cerrarConexionTcp()
{
  Serial3.write("AT+CIPSHUT\r\n");
  return esperaRespuesta(
    "AT+CIPSHUT\r\n\r\nSHUT OK\r\n",
    500, 50
  );
}

int estadoIP ()
{
  Serial3.write("AT+CIPSTATUS\r\n");
  return esperaRespuesta (
    "AT+CIPSTATUS\r\n\r\nOK\r\n\r\nSTATE: IP INITIAL\r\n",
    500, 500
  );
}

int mux0 ()
{
  Serial3.write("AT+CIPMUX=0\r\n");  
  return esperaRespuesta (
    "AT+CIPMUX=0\r\n\r\nOK\r\n",
    500, 50
  );
}

int setAPN ()
{
  Serial3.write("AT+CSTT=\"ba.amx\",\"\",\"\"\r\n");
  return esperaRespuesta (
    "AT+CSTT=\"ba.amx\",\"\",\"\"\r\n\r\nOK\r\n",
    500, 50
  );
}

int conectar ()
{
  Serial3.write("AT+CIICR\r\n");
  return esperaRespuesta (
    "AT+CIICR\r\n\r\nOK\r\n",
    5000, 5000
  );
}

int levantarIP ()
{
  Serial3.write("AT+CIFSR\r\n");  
  delay (1000);
  limpiarSerial3();
  return 1;
}

int conectarAlServidor()
{
  // fum.federicogon.com.ar = 166.78.236.198
  
  Serial3.write("AT+CIPSTART= \"TCP\",\"201.212.74.226\",\"1337\"\r\n");
  return esperaRespuesta (
    "AT+CIPSTART= \"TCP\",\"201.212.74.226\",\"1337\"\r\n\r\nOK\r\n\r\nCONNECT OK\r\n",
    5000, 5000
  );
}

int mandar()
{
  Serial3.write("AT+CIPSEND\r\n");
  
  //AT+CIPSEND[CR][LF]
  //[CR][LF]
  //>                    <--- pico y espacio... (limpiar despues del pico)

  if (esperaRespuesta ("AT+CIPSEND\r\n\r\n>", 500, 50)) {
    limpiarSerial3();
    
    int stationID = 1;
    float vbat = analogRead(0) * 0.01941;
    unsigned long time = 1415435753;
    float lat = 32.123;
    float lon = 60.456;
    
    // metodo (GET)
    Serial3.print("GET /reads/process?format=json&stationID=");
    Serial3.print(stationID, DEC);
    Serial3.print("&sensorCode=vbat&value=");
    Serial3.print(vbat, 2);
    Serial3.print("&time=");
    Serial3.print(time);
    Serial3.print("&lat=");
    Serial3.print(lat, 6);
    Serial3.print("&long=");
    Serial3.print(lon, 6);
    Serial3.print(" HTTP/1.1\r\n");
    
    // headers
    Serial3.print("From: hav29a@gmail.com\r\n");
    Serial3.print("Host: fum.federicogon.com.ar\r\n");
    Serial3.print("\r\n");
    
    // fin (CTRL+Z)
    Serial3.write((char)26);
    
    // ahora debería esperar un 200...
    
  } else {
    return 0;
  }
  
  delay (5000);
  limpiarSerial3();
  
  return 1;
}

void setup ()
{
  delay(1000); 
  pinMode(PIN_ONOFF, OUTPUT); // digital on off
  Serial.begin (9600); // host
  Serial3.begin(9600); // modem
}

int trabajar ()
{
  limpiarSerial3();
  
  if (adjuntoALaRed()) {
    Serial.println("ADJ OK");
  } else {
    Serial.println("ADJ FAIL");
    return 0;
  }
  
  if (cerrarConexionTcp()) {
    Serial.println("SHUT OK");
  } else {
    Serial.println("SHUT FAIL");
    return 0;    
  }
  
  if (estadoIP()) {
    Serial.println("IP STAT OK");
  } else {
    Serial.println("IP STAT FAIL");
    return 0;
  }
  
  if (mux0()) {
    Serial.println("MUX OK");
  } else {
    Serial.println("MUX FAIL");
    return 0;
  }
  
  if (setAPN()) {
    Serial.println("APN OK");
  } else {
    Serial.println("APN FAIL");
    return 0;
  }
  
  if (conectar()) {
    Serial.println("CON OK");
  } else {
    Serial.println("CON FAIL");
    return 0;
  }
  
  if (levantarIP()) {
    Serial.println("IPUP OK");
  } else {
    Serial.println("IPUP FAIL");
    return 0;
  }
  
  if (conectarAlServidor()) {
    Serial.println("SERVER OK");
  } else {
    Serial.println("SERVER FAIL");
    return 0;
  }
  
  if (mandar()) {
    Serial.println("SEND OK");
  } else {
    Serial.println("SEND FAIL");
    return 0;
  }
 
  if (cerrarConexionTcp()) {
    Serial.println("SHUT OK");
  } else {
    Serial.println("SHUT FAIL");
    return 1; // igual devuelvo true aca...
  }
  
  return 1;
}

void encenderModem ()
{
  Serial.println("Modem On");
  onOff();
  Serial.println("Espera 25 seg...");
  delay (25000);
}

void apagarModem ()
{
  Serial.println("Modem Off");
  onOff();
}

void loop ()
{
  //if ((Serial.available()) && (Serial.read() == '!')) {  
    for (int i=0; i<3; i++) {
      encenderModem();
      if (trabajar()) {
        apagarModem();
        break;
      }
      apagarModem();
      delay (5000);
    }
    
    // espero 1 hora
    // el trabajo tarda 48 segundos
    for (int i=0; i<(3600-48); i++)
      delay (1000);
  //}
}

